package MyScanner;

import java.util.HashSet;
import java.util.Set;
import java.util.Stack;

//状态机，用于处理词法分析时的状态转换
public class DFA {

    //这里是DFA的状态表，和Token中同名的Token标识符不同
    public enum STATE{
        //0、各种终止态
        INITIAL,    //初始态
        IDENTIFIER, //标识符(终止态)
        KEYWORD,    //关键字(终止态)
        INTEGER_CONSTANT,   //整型常量(终止态)
        FLOATING_CONSTANT,  //浮点常量(终止态)
        CHARACTER_CONSTANT, //字符常量(终止态)
        STRING_LITERAL,     //字符串常量(终止态)
        OPERATORS,          //操作符,界符(终止态)
        EOF,                //结束符号(终止态)
        NULL,               //无意义符号，用于空格等状态
        ERROR,              //错误态，识别到错误的情况
        BACK,               //回退一次

        //以下为各个中间态
        //1、识别标识符，字符常量，字符串常量使用的状态

        MidIdentifier,   //标识符中间态
        UPrefix,         //以U|u标识的字/字符串前缀
        LPrefix,         //以L|l标识的字/字符串前缀
        U8Prefix,        //以u8开头的字符串前缀
        MidChar,            //字符常量中间态
        CHAR_WAIT,          //字符常量阻塞态
        EscapeChar,         //含有转义\的字符常量中间态
        EscapeStr,          //含有转义\的字符串常量中间态
        MidStr,             //字符串常量中间态
        STR_WAIT,            //字符串常量阻塞态

        //2、识别整形常量、浮点常量使用的状态
        NoZeroDecInt,             //非0十进制整数
        Zero,                     //以0开头，可能是十进制/十六进制小数，也可能是10，8，16进制整数
        OctInt,                   //8进制整数
        HexInt,                   //16进制整数
        DecFloatFrac,             //十进制浮点数小数部分
        IntSuffix,                 //整数后缀部分
        HexFloatFrac,             //16进制小数部分
        Exponent,                 // e|E|p|P标识处
        OrderPart,                //阶码部分
        FLSuffix,                 //浮点数的F/L后缀

        // 2.1 识别u, l, ul, ull, lu, llu ll 这7种整数后缀的状态
        ULSuffix,
        ULLSuffix,
        LUSuffix,
        LLUSuffix,
        USuffix,
        LSuffix,
        LLSuffix,

        //3、识别运算符，界限符使用的状态
        MidSymbol
    }

    //member vars
    private STATE curState;
    private final Set<STATE> endStateSet; //终态集合，需要在DFA建立时设置好
    private final Stack<STATE> stateStack;

    public DFA()
    {
        //Init
        curState = STATE.INITIAL;
        endStateSet = new HashSet<>();
        stateStack = new Stack<>();
        stateStack.push(curState);

        //add endStates
        endStateSet.add(STATE.IDENTIFIER);
        endStateSet.add(STATE.KEYWORD);
        endStateSet.add(STATE.INTEGER_CONSTANT);
        endStateSet.add(STATE.FLOATING_CONSTANT);
        endStateSet.add(STATE.CHARACTER_CONSTANT);
        endStateSet.add(STATE.STRING_LITERAL);
        endStateSet.add(STATE.OPERATORS);
        endStateSet.add(STATE.EOF);
        endStateSet.add(STATE.NULL);
        endStateSet.add(STATE.ERROR);
    }

    //状态转移
    public void stateTransition(char curCh, String curStr)
    {
        //特殊的回退状态，用来处理特殊情况。
        if(curState == STATE.BACK)
        {
            stateStack.pop();   //弹出栈顶上一次确定的状态
            stateStack.pop();   //弹出栈顶上一次确定的状态
            curState = stateStack.peek();
        }


        //初始状态
        if(curState == STATE.INITIAL)
        {
            //字符、字符串常量、标识符部分
            if(curCh == 'u' || curCh == 'U')
                curState = STATE.UPrefix;
            else if(curCh == 'l' || curCh == 'L')
                curState = STATE.LPrefix;
            else if(curCh == '_' || isLetter(curCh))    //标识符前缀，让其转移优先级低于u/l前缀
                curState = STATE.MidIdentifier;
            else if(curCh == '\'')  //单引号
                curState = STATE.MidChar;
            else if(curCh == '\"')  //双引号
                curState = STATE.MidStr;
            //属于标识符，界符
            else if(StdElements.isSymbol("" + curCh))
                curState = STATE.MidSymbol;

            //数字识别
            else if(!isNoZeroDigital(curCh) && isDigital(curCh))    //0开头
                curState = STATE.Zero;
            else if(isNoZeroDigital(curCh))     //1-9开头
                curState = STATE.NoZeroDecInt;
            //其他目标 如 \n,' '之类的无效字符，都视为NULL
            else if(curCh == '\u001a')
                curState = STATE.EOF;
            else
                curState = STATE.NULL;
        }

        //1、字符串常量，字符常量，标志符号识别
        //标识符中间态
        else if(curState == STATE.MidIdentifier)
        {
            if(curCh == '_' || isLetter(curCh) || isDigital(curCh))
                curState = STATE.MidIdentifier;
            else
                curState = STATE.IDENTIFIER;
        }

        //u/U前缀
        else if(curState == STATE.UPrefix)
        {
            if(curCh == '8')    //u8前缀
                curState = STATE.U8Prefix;
            else if(curCh == '_' || isDigital(curCh) || isLetter(curCh))    //不为前缀，转会标识符
                curState = STATE.MidIdentifier;
            else if(curCh == '\'')  //单引号
                curState = STATE.MidChar;
            else if(curCh == '\"')  //双引号
                curState = STATE.MidStr;
            else
                curState = STATE.IDENTIFIER;
        }

        //L/l前缀
        else if(curState == STATE.LPrefix)
        {
            if(curCh == '_' || isDigital(curCh) || isLetter(curCh))    //不为前缀，转会标识符
                curState = STATE.MidIdentifier;
            else if(curCh == '\'')  //单引号
                curState = STATE.MidChar;
            else if(curCh == '\"')  //双引号
                curState = STATE.MidStr;
            else
                curState = STATE.IDENTIFIER;
        }

        //u8前缀
        else if(curState == STATE.U8Prefix)
        {
            if(curCh == '\"')
                curState = STATE.MidStr;
            else if(curCh == '_' || isDigital(curCh) || isLetter(curCh))
                curState = STATE.MidIdentifier;
            else
                curState = STATE.IDENTIFIER;
        }

        //字符常量中间态
        else if(curState == STATE.MidChar)
        {
            if(curCh == '\\')   //转义字符情况
                curState = STATE.EscapeChar;
            else if(curCh == '\'')  //单引号，字符中间态结束
                curState = STATE.CHAR_WAIT;
            else
                curState = STATE.MidChar;   //其他状态不变
        }

        //字符转义中间态
        else if(curState == STATE.EscapeChar)
        {
            //读取任何字符都返回字符中间态
            curState = STATE.MidChar;
        }

        //字符阻塞态
        else if(curState == STATE.CHAR_WAIT)
        {
            curState = STATE.CHARACTER_CONSTANT;
        }

        //字符串常量中间态
        else if(curState == STATE.MidStr)
        {
            if(curCh == '\\')
                curState = STATE.EscapeStr;
            else if(curCh == '\"')
                curState = STATE.STR_WAIT;
            else
                curState = STATE.MidStr;
        }

        //字符串转义中间态
        else if(curState == STATE.EscapeStr)
        {
            curState = STATE.MidStr;
        }

        //字符串阻塞态
        else if(curState == STATE.STR_WAIT)
        {
            curState = STATE.STRING_LITERAL;
        }


        //2、整数产量，浮点数产常量识别
        else if(curState == STATE.Zero)     //0开头，可能为8进制，16进制或单纯的整数0
        {
            if(isOctNumber(curCh))
                curState = STATE.OctInt;
            else if(curCh == 'x' || curCh == 'X')           //0x 0X 的十六进制前缀
                curState = STATE.HexInt;
            else if(curCh == '.')   //小数点,为10进制小数
                curState = STATE.DecFloatFrac;
            else if(curCh == 'u'|| curCh == 'U' || curCh == 'l' || curCh == 'L')    //ul, ull, llu, lu 的整数后缀
                curState = STATE.IntSuffix;
            else if(curCh == 'E' || curCh == 'e')
                curState = STATE.Exponent;
            else    //其他情况就是单纯的0常量，进入终止态
                curState = STATE.INTEGER_CONSTANT;
        }

        else if(curState == STATE.NoZeroDecInt) //1-9开头的十进制数
        {
            if(isDigital(curCh))
                curState = STATE.NoZeroDecInt;
            else if(curCh == '.')   //10进制小数部分
                curState = STATE.DecFloatFrac;
            else if(curCh == 'u'|| curCh == 'U' || curCh == 'l' || curCh == 'L')    //ul, ull, llu, lu 的整数后缀
                curState = STATE.IntSuffix;
            else if(curCh == 'E' || curCh == 'e')
                curState = STATE.Exponent;
            else    //其他情况就是单纯的整数常量，进入终止态
                curState = STATE.INTEGER_CONSTANT;
        }

        else if(curState == STATE.DecFloatFrac) //10进制小数部分
        {
            if(isDigital(curCh))
                curState = STATE.DecFloatFrac;
            else if(curCh == 'e' || curCh == 'E')   //阶码部分
                curState = STATE.Exponent;
            else    //其他情况就是单纯的浮点数常量，进入终止态
                curState = STATE.FLOATING_CONSTANT;
        }

        else if(curState == STATE.Exponent) //阶码部分，只能是 - + [0-9] ' '
        {
            if(isDigital(curCh) || curCh == '-' || curCh == '+')
                curState = STATE.OrderPart;
            else
                curState = STATE.BACK;  //此时不可能是指数形式，需要回退一次把当前的状态转化为最近的一个终止态。
        }

        else if(curState == STATE.OrderPart)    //阶码数值部分
        {
            if(isDigital(curCh))
                curState = STATE.OrderPart;
            else if(curCh == 'f' || curCh == 'F' || curCh == 'L' || curCh == 'l')   //浮点数尾缀出现
                curState = STATE.FLSuffix;
            else
                curState = STATE.FLOATING_CONSTANT;
        }

        else if(curState == STATE.OctInt)   //八进制整数
        {
            if(isOctNumber(curCh))
                curState = STATE.OctInt;
            else if(curCh == 'u' || curCh == 'U' || curCh == 'L' || curCh == 'l')
                curState = STATE.IntSuffix; //整数常量后缀
            else
                curState = STATE.INTEGER_CONSTANT;  //整型常量
        }

        else if(curState == STATE.HexInt)   //十六进制整数
        {
            if(isHexNumber(curCh))
                curState = STATE.HexInt;
            else if(curCh == '.')   //十六进制小数
                curState = STATE.HexFloatFrac;
            else if(curCh == 'u' || curCh == 'U' || curCh == 'L' || curCh == 'l')
                curState = STATE.IntSuffix; //整数常量后缀
            else if(curCh == 'p' || curCh == 'P')
                curState = STATE.Exponent;
            else
                curState = STATE.INTEGER_CONSTANT;  //整型常量
        }

        else if(curState == STATE.HexFloatFrac) //十六进制浮点数小数部分
        {
            if(isHexNumber(curCh))
                curState = STATE.HexFloatFrac;
            else if(curCh == 'p' || curCh == 'P')   //转移到阶码标志部分
                curState = STATE.Exponent;
            else
                curState = STATE.BACK;
        }

        else if(curState == STATE.FLSuffix)
        {
            curState = STATE.FLOATING_CONSTANT;
        }

        //2.1 ul符号后缀
        else if(curState == STATE.USuffix)
        {
            if(curCh == 'l' || curCh == 'L')
                curState = STATE.ULSuffix;
            else
                curState = STATE.INTEGER_CONSTANT;
        }

        else if(curState == STATE.ULSuffix)
        {
            if(curCh == 'l' || curCh == 'L')
                curState = STATE.ULLSuffix;
            else
                curState = STATE.INTEGER_CONSTANT;
        }

        else if(curState == STATE.ULLSuffix)
        {
            curState = STATE.INTEGER_CONSTANT;
        }

        else if(curState == STATE.LSuffix)
        {
            if(curCh == 'L' || curCh == 'l')
                curState = STATE.LLSuffix;
            else if(curCh == 'u' || curCh == 'U')
                curState = STATE.LUSuffix;
            else
                curState = STATE.INTEGER_CONSTANT;
        }

        else if(curState == STATE.LLSuffix)
        {
            if(curCh == 'u' || curCh =='U')
                curState = STATE.LLUSuffix;
            else
                curState = STATE.INTEGER_CONSTANT;
        }

        else if(curState == STATE.LUSuffix)
        {
            curState = STATE.INTEGER_CONSTANT;
        }

        else if(curState == STATE.LLUSuffix)
        {
            curState = STATE.INTEGER_CONSTANT;
        }




        //3、运算符号，界限符号的识别
        else if(curState == STATE.MidSymbol)
        {
            if(StdElements.isSymbol(curStr + curCh))
                curState = STATE.MidSymbol;
            else
                curState = STATE.OPERATORS;
        }

        //以 IntSuffix为新的起点进行空转
        if(curState == STATE.IntSuffix)
        {
            if (curCh == 'u' || curCh == 'U')
                curState = STATE.USuffix;
            else if(curCh == 'L' || curCh == 'l')
                curState = STATE.LSuffix;
        }
        //完成状态转移后，需要将当前状态压栈
        stateStack.push(curState);

    }

    //状态确认
    public boolean isEndState()
    {
        return endStateSet.contains(curState);
    }
    //获取当前状态
    public STATE getCurState()
    {
        return curState;
    }
    //初始化
    public void initDFA()
    {
        curState = STATE.INITIAL;
        stateStack.clear();
        stateStack.push(curState);
    }


    //判断函数
    private boolean isNoZeroDigital(char ch)   //非零数字
    {
        return  '1' <= ch && ch <= '9';
    }

    private boolean isDigital(char ch)  //任意数字
    {
        return '0' <= ch && ch <= '9';
    }

    private boolean isLetter(char ch)   //任意字母
    {
        return  ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z');
    }

    private boolean isOctNumber(char ch)    //八进制数字
    {
        return ('0' <= ch && ch <= '7');
    }

    private boolean isHexNumber(char ch)    //十六进制数字
    {
        return ('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F') || isDigital(ch);
    }
}
